package com.duobaoyu.dby.supply.api.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.math.Money;
import com.duobaoyu.dby.channel.adapter.enums.biz.order.OrderStatusEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.product.GoodsStatusEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.product.ProductTypeEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.refund.AfterSaleTypeEnum;
import com.duobaoyu.dby.channel.boundary.bean.refund.result.AfterSaleAttributesResult;
import com.duobaoyu.dby.channel.boundary.bean.refund.result.AfterSaleReturnAddressResult;
import com.duobaoyu.dby.common.core.constant.CommonConstants;
import com.duobaoyu.dby.common.core.convert.bean.ReferenceMapper;
import com.duobaoyu.dby.common.core.util.DateUtils;
import com.duobaoyu.dby.common.mybatis.util.EnumUtils;
import com.duobaoyu.dby.supply.biz.client.boundary.order.bean.bo.OrderBO;
import com.duobaoyu.dby.supply.biz.client.boundary.order.bean.bo.OrderProductBO;
import com.duobaoyu.dby.supply.biz.util.CustomReferenceMapper;
import com.duobaoyu.dby.supply.common.biz.bo.refund.*;
import com.duobaoyu.dby.supply.common.biz.remote.dto.refund.AfterSaleApplyDTO;
import com.duobaoyu.dby.supply.common.biz.remote.dto.refund.AfterSaleWayBillDTO;
import com.duobaoyu.dby.supply.common.biz.remote.to.refund.AfterSaleAddressTO;
import com.duobaoyu.dby.supply.common.biz.remote.to.refund.AfterSaleAttributesTO;
import com.duobaoyu.dby.supply.common.biz.remote.to.refund.ApplyAfterSaleDetailTO;
import com.duobaoyu.dby.supply.common.biz.remote.to.refund.ApplyAfterSaleTO;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.mapstruct.Builder;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by shuming on 2023/10/7 15:56
 */
@Mapper(uses = {ReferenceMapper.class, CustomReferenceMapper.class}, builder = @Builder(disableBuilder = true), componentModel = CommonConstants.COMPONENT_MODEL)
public interface AfterSaleBizServiceConverter {

    default ApplyAfterSaleTO assembleApplyAfterSale(AfterSaleApplyOutBO afterSaleCreateResult) {
        List<AfterSaleApplyOutBO.Result> results = afterSaleCreateResult.getResults();
        List<ApplyAfterSaleTO.ApplyResultTO> itemResults = results.stream().map(e -> {
            ApplyAfterSaleTO.ApplyResultTO item = new ApplyAfterSaleTO.ApplyResultTO();
            item.setBizAfterSaleSn(e.getBizAfterSaleSn());
            item.setOrderSn(e.getOrderSn());
            item.setAfterSaleSn(e.getAfterSaleSn());
            item.setSkuCode(CollUtil.getFirst(e.getSkuCodes()));
            return item;
        }).collect(Collectors.toList());
        return ApplyAfterSaleTO.builder().results(itemResults).build();
    }


    AfterSaleCreateInBO convertAfterSaleApply(AfterSaleApplyDTO afterSaleApply);

    AfterSalePickUpBO convertAfterSalePickUp(AfterSaleApplyDTO.PickupWareInfoDTO pickupWareInfo);

    AfterSaleReturnShipmentBO convertAfterSaleReturnShipment(AfterSaleApplyDTO.ReturnWareInfoDTO returnWareInfo);


    AfterSaleContactInfoBO convertAfterSaleCustomerInfo(AfterSaleApplyDTO.CustomerInfo customerInfo);

    default AfterSaleWayBillInBO convertAfterSaleWayBill(AfterSaleWayBillDTO afterSaleWayBill, AfterSaleOutBO afterSale) {
        AfterSaleItemOutBO afterSaleItemOut = afterSale.getItems().stream()
                .filter(e -> Objects.equals(e.getSkuCode(),afterSaleWayBill.getSkuCode()))
                .findFirst().orElse(new AfterSaleItemOutBO());
        AfterSaleWayBillInBO waybill = new AfterSaleWayBillInBO();
        waybill.setAfterSaleSn(afterSaleItemOut.getAfterSaleSn());
        waybill.setOrderSn(afterSaleItemOut.getOrderSn());
        waybill.setSkuCode(afterSaleItemOut.getSkuCode());
        waybill.setSkuName(afterSaleItemOut.getSkuName());
        waybill.setChannelSkuCode(afterSaleItemOut.getChannelSkuCode());
        waybill.setProductType(ProductTypeEnum.getProductTypeEnum(afterSaleItemOut.getProductType()).getValue());
        waybill.setSendingBackQuantity(afterSaleWayBill.getProductNum());
        waybill.setDeliverDate(LocalDateTime.parse(afterSaleWayBill.getDeliverDate(), DateUtils.DEFAULT_DATE_TIME_FORMATTER));
        waybill.setExpressCode(afterSaleWayBill.getExpressCode());
        waybill.setExpressCompanyCode(afterSaleWayBill.getExpressCompanyCode());
        waybill.setExpressCompany(afterSaleWayBill.getExpressCompany());
        waybill.setFreightAmount(afterSaleWayBill.getFreightMoney());
        return waybill;
    }

    List<AfterSaleAttributesTO.AfterSaleReason> assembleAfterSaleReasons(List<AfterSaleAttributesResult.AfterSaleReason> afterSaleReasons);


    default AfterSaleAttributesTO.AfterSaleReason assembleAfterSaleReason(AfterSaleAttributesResult.AfterSaleReason afterSaleReason) {
        if (Objects.isNull(afterSaleReason)) {
            return null;
        }
        AfterSaleAttributesTO.AfterSaleReason reason = new AfterSaleAttributesTO.AfterSaleReason();
        reason.setAfterSaleType(afterSaleReason.getAfterSaleType().getValue());
        List<AfterSaleAttributesResult.ReasonDetail> reasons = afterSaleReason.getReasonDetails();
        if (CollectionUtils.isNotEmpty(reasons)) {
            reason.setReasons(reasons.stream().map(e -> {
                AfterSaleAttributesTO.Reason r = new AfterSaleAttributesTO.Reason();
                r.setNeedVoucher(e.getNeedVoucher());
                r.setReasonCode(e.getChannelAfterSaleReasonCode());
                r.setReasonName(e.getChannelAfterSaleReason());
                return r;
            }).collect(Collectors.toList()));
        }
        return reason;
    }

    default AfterSaleCreateSplitInBO convertAfterSaleCreateSplit(AfterSaleApplyDTO afterSaleApply, List<OrderBO> orders) {

        Map<String, List<AfterSaleApplyDTO.Content>> afterSaleOrder = afterSaleApply.getContents().stream()
                .collect(Collectors.groupingBy(AfterSaleApplyDTO.Content::getOrderSn));
        Map<String, OrderBO> orderMap = orders.stream()
                .collect(Collectors.toMap(OrderBO::getOrderSn, Function.identity()));
        Map<String, OrderProductBO> orderItemMap = orders.stream().flatMap(e -> e.getOrderProductList().stream())
                .collect(Collectors.toMap(OrderProductBO::getSkuCode, Function.identity()));
        Map<String, AfterSalePickUpBO> pickUpMap = Maps.newHashMap();
        Map<String, AfterSaleReturnShipmentBO> returnShipmentMap = Maps.newHashMap();
        Map<String, AfterSaleContactInfoBO> customerInfoMap = Maps.newHashMap();
        List<AfterSaleCreateSplitInBO.Item> itemSummary = Lists.newArrayList();
        afterSaleOrder.forEach((k, v) -> {
            v.forEach(order -> {
                pickUpMap.put(order.getOrderSn(), convertAfterSalePickUp(order.getPickupWareInfo()));
                returnShipmentMap.put(order.getOrderSn(), convertAfterSaleReturnShipment(order.getReturnWareInfo()));
                customerInfoMap.put(order.getOrderSn(), convertAfterSaleCustomerInfo(order.getCustomerInfo()));
            });

            List<AfterSaleApplyDTO.Sku> skus = v.stream()
                    .flatMap(e -> e.getSkus().stream()).collect(Collectors.toList());
            List<AfterSaleCreateSplitInBO.Item> items = skus.stream()
                    .map(e -> {
                        OrderProductBO orderProduct = orderItemMap.get(e.getSkuCode());
                        AfterSaleCreateSplitInBO.Item item = new AfterSaleCreateSplitInBO.Item();
                        item.setOrderSn(k);
                        item.setSkuCode(e.getSkuCode());
                        item.setApplyNum(e.getApplyNum());
                        item.setQuestionDesc(e.getQuestionDesc());
                        item.setQuestionPic(e.getQuestionPic());
                        item.setReasonCode(e.getReasonCode());
                        item.setReasonName(e.getReasonName());
                        item.setGoodStatus(convertGoodStatus(e.getReceived(), orderMap.get(k)).getValue());
                        // 退款或退货时，当业务没有传递退款金额时，使用支付的金额
                        if (EnumUtils.eq(AfterSaleTypeEnum.REFUND,afterSaleApply.getAfterSaleType())
                                || EnumUtils.eq(AfterSaleTypeEnum.RETURNED,afterSaleApply.getAfterSaleType())) {
                            item.setApplyRefundAmount(Optional.ofNullable(e.getApplyRefundAmount())
                                    .orElse(new Money(orderProduct.getChannelPayAmount()).divide(orderProduct.getSkuNum()).multiply(e.getApplyNum()).getAmount()));
                        }
                        return item;
                    }).collect(Collectors.toList());
            itemSummary.addAll(items);

        });
        AfterSaleCreateSplitInBO ret = new AfterSaleCreateSplitInBO();
        ret.setSupplyTradeSn(afterSaleApply.getSupplyTradeSn());
        ret.setServerName(afterSaleApply.getServerName());
        ret.setShowServerName(afterSaleApply.getShowServerName());
        ret.setBizAfterSaleSn(afterSaleApply.getBizAfterSaleSn());
        ret.setAfterSaleType(afterSaleApply.getAfterSaleType());
        ret.setItems(itemSummary);
        ret.setPickUpMap(pickUpMap);
        ret.setReturnShipmentMap(returnShipmentMap);
        ret.setCustomerInfoMap(customerInfoMap);
        return ret;
    }

    /**
     * @param received 是否收到货
     * @param order    订单
     * @return
     */
    @Deprecated
    default GoodsStatusEnum convertGoodStatus(Boolean received, OrderBO order) {
        received = Optional.ofNullable(received).orElse(false);
        // 售中
        if (EnumUtils.neq(OrderStatusEnum.COMPLETE,order.getOrderStatus())) {
            if (EnumUtils.eq(OrderStatusEnum.WAIT_SHIP,order.getOrderStatus())) {
                return GoodsStatusEnum.REFUND_WAIT_SELLER_SEND;
            } else {
                return received ? GoodsStatusEnum.REFUND_BUYER_RECEIVED : GoodsStatusEnum.REFUND_WAIT_BUYER_RECEIVE;
            }
        }
        // 售后
        return received ? GoodsStatusEnum.AFTERSALE_BUYER_RECEIVED : GoodsStatusEnum.AFTERSALE_BUYER_NOT_RECEIVED;
    }

	CustomerReturnAddressBO toCustomerReturnAddress(AfterSaleReturnAddressResult addressResult);

    ApplyAfterSaleDetailTO toApplyAfterSaleDetail(AfterSaleOutBO afterSaleOut);

	@Mapping(target = "afterServiceTel", source = "channelAfterServiceTel")
	@Mapping(target = "afterServiceReceiver", source = "channelAfterServiceReceiver")
	@Mapping(target = "afterServicePhone", source = "channelAfterServicePhone")
	@Mapping(target = "afterServiceAddress", source = "channelAfterServiceAddress")
	AfterSaleAddressTO assembleLocalAfterSaleAddress(CustomerReturnAddressBO customerReturnAddress);
}
